#include <stdio.h>
#include <time.h>
#include <iostream>
#include <fstream>
#include <string>
#include "logmanager.h"
#include <stdarg.h>
#include <string.h>

#ifdef _WIN32
#include <direct.h>
#define MKDIR(a) mkdir(a)
#define MTPROTECT()
#define MTUNPROTECT()
#else
#include <pthread.h>
#include <sys/stat.h>
#define MKDIR(a) mkdir(a, 777)
pthread_mutex_t logmutex = PTHREAD_MUTEX_INITIALIZER;
#define MTPROTECT()  pthread_mutex_lock(&logmutex)
#define MTUNPROTECT() pthread_mutex_unlock(&logmutex)

#endif

using namespace std;

CLog MainLog, DateLog;
std::auto_ptr<CLog> CLog::sm_inst;

extern int debug;


//*********************************************************************
// CONSTRUCTOR & DESTRUCTOR
//*********************************************************************

CLog::CLog()
{
    // Set file handler to NULL
    m_pLogFile = NULL;
}

//*********************************************************************
// PUBLIC FUNCTIONS
//*********************************************************************

CLog * CLog::Instance()
{
    if(sm_inst.get() == 0)
        sm_inst = auto_ptr<CLog>(new CLog);
    return sm_inst.get();

}

//=====================================================================

void CLog::CreateLog(string sFilepath, string sFilename, _Openmode flag)
{
	OpenFlag = flag;
    // Create the new log
    m_pLogFile = new ofstream;

    // string dir("dir/dir1/");

    if (MKDIR(sFilepath.c_str()) == -1)    // Create the directory
    {
        // std::cerr << "Error: " << strerror(errno);
    }

	Filepath = sFilepath;

	if (FlagContain(TimeAsFilename))
		Filename = GetDate();
	else 
		Filename = sFilename;

	if (FlagContain(OverWrite))
	m_pLogFile->open ((Filepath + "/" + Filename).c_str(), ios_base::trunc);
	else
    m_pLogFile->open ((Filepath + "/" + Filename).c_str(), ios_base::app);

}

//=====================================================================

void CLog::Log(string sText)
{
	MTPROTECT();
    // Check if log is already created
    if (m_pLogFile == NULL)
        return;

	// Check if should open new file of date
	if (FlagContain(TimeAsFilename))
	{
		if (Filename != GetDate())
		{
			CloseLog();
			CreateLog(Filepath, "", OpenFlag);
		}
	}

    // Should we add time to beginning of string?
    if (FlagContain(EnableTimestamp))
    {
        sText = GetTime() + " => " + sText;
    }
    // Log text
    *m_pLogFile << sText << endl;
	MTUNPROTECT();
}

//=====================================================================

void CLog::CloseLog()
{
    // Close file
    m_pLogFile->close();

    // Delete object
    delete m_pLogFile;

    // Set handle to NULL
    m_pLogFile = NULL;
}

//=====================================================================

void CLog::SetEnableTimestamp(bool bEnable)
{
    // Set timestamp option
}

//*********************************************************************
// PRIVATE FUNCTIONS
//*********************************************************************

string CLog::GetTime()
{
  time_t rawtime;
  struct tm * timeinfo;
  char buffer [80];

  time ( &rawtime );
  timeinfo = localtime ( &rawtime );

  strftime (buffer,80,"%c",timeinfo);
  return buffer;
}

string CLog::GetDate()
{
  time_t rawtime;
  struct tm * timeinfo;
  char buffer [80];

  time ( &rawtime );
  timeinfo = localtime ( &rawtime );

  strftime (buffer,80,"%Y%m%d",timeinfo);
  return buffer;
}


extern "C"
int LogInit ()
{	
	MainLog.CreateLog("/var/log/venus", "startup", (CLog::_Openmode)(CLog::EnableTimestamp|CLog::OverWrite));// | CLog::TimeAsFilename));
	DateLog.CreateLog("/var/log/venus/common", "", (CLog::_Openmode)(CLog::EnableTimestamp|CLog::TimeAsFilename));// | CLog::TimeAsFilename));
	return 1;
}


extern "C"
int MLog (const char *c, ...)
{
	char buffer[1000];      
	va_list ap;

	memset(buffer, 0, sizeof(buffer)); 

	va_start(ap, c);
	vsnprintf(buffer, sizeof(buffer) - 1, c, ap);
	va_end(ap);
	MainLog.Log(buffer);
	return 1;
}

extern "C"
int DLog (const char *c, ...)
{
	char buffer[1000];      
	va_list ap;

	memset(buffer, 0, sizeof(buffer)); 

	va_start(ap, c);
	vsnprintf(buffer, sizeof(buffer) - 1, c, ap);
	va_end(ap);
	DateLog.Log(buffer);
	return 1;
}

enum DEBUG_LEVEL
{
	DEBUG_STDOUT,
	DEBUG_STDERR,
	DEBUG_MAIN,
	DEBUG_DATE,
	DEBUG_BOTH
};


extern "C"
int Vdebug (DEBUG_LEVEL level, const char *c, ...)
{
	char buffer[1000];      
	va_list ap;

	memset(buffer, 0, sizeof(buffer)); 

	va_start(ap, c);
	vsnprintf(buffer, sizeof(buffer) - 1, c, ap);
	va_end(ap);
	if (debug)
		printf("%s\n", buffer);
	switch (level)
	{
	case DEBUG_STDOUT:
		break;
	case DEBUG_STDERR:
		break;
	case DEBUG_DATE:
		DateLog.Log(buffer);
		break;
	case DEBUG_MAIN:
		MainLog.Log(buffer);
		break;
	case DEBUG_BOTH:
		DateLog.Log(buffer);
		MainLog.Log(buffer);
		break;
	default:
		break;
	}	
	return 1;
}